package klimuts.periodicals.data;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;

public class ConnectionPool {
	private static final String DRIVER_NAME = "com.mysql.jdbc.Driver";
	private static String url=null;
	private static String user=null;
	private static String password=null;
	private static int maxConn=10;
	private static ConnectionPool instance=null;
	private static int clients=0;
	private static ArrayList free=new ArrayList();//array for free connections
	private static PrintWriter log=null;
	
	private ConnectionPool(String url, String user, String password, int maxConn){
		this.url=url;
		this.user=user;
		this.password=password;
		this.maxConn=maxConn;
		String logFile="ConnectionPool.log";
		try{
			log=new PrintWriter(new FileWriter(logFile, true), true);
		}catch(IOException e){
			System.err.println("Can't open the log file: "+logFile);
			log=new PrintWriter(System.err);
		}
		loadDrivers();
	}
	
	private void loadDrivers() {
		try{
			Driver driver=(Driver)Class.forName(DRIVER_NAME).newInstance();
			DriverManager.registerDriver(driver);
			log("Registered JDBC driver ");
		}catch(Exception e){
			log("Can't register JDBC driver");
		}
	}
	
	static synchronized public ConnectionPool getInstance(){
		if(instance==null){
			instance=new ConnectionPool("jdbc:mysql://localhost:3306/periodicals?useUnicode=true&characterEncoding=utf8", "root", "47", 10);
		}
		clients++;
		return instance;
	}
	
	static synchronized public ConnectionPool getInstance(String url, String user, String password, int maxConn){
		if(instance==null){
			instance=new ConnectionPool(url, user, password, maxConn);
		}
		clients++;
		return instance;
	}
	
	public synchronized Connection getConnection(){
		Connection con=null;
		if(!free.isEmpty()){
			con=(Connection)free.get(free.size()-1);
			free.remove(con);
			
			try{
				if(con.isClosed()){
					log("Removed bad connection");
					con=getConnection();
				}
			}catch(SQLException e){
				log("Removed bad connection");
				con=getConnection();
			}catch(Exception e){
				log("Removed bad connection");
				con=getConnection();
			}
			log("Get connection from list free connections");
		}else{
			con=newConnection();
		}
		return con;
	}
	
	private Connection newConnection(){
		Connection con=null;
		try{
			if(user==null){
				con=DriverManager.getConnection(url);
			}else{
				con=DriverManager.getConnection(url, user, password);
			}
			log("Create a new connection in pool");
		}catch(SQLException e){
			log("Can't create a new connection for "+url);
			return null;
		}
		return con;
	}
	
	public synchronized void freeConnection(Connection con){
		if(con!=null){
			if(free.size()<maxConn){
				free.add(con);
				log("Free connection");
			}else{
				try{
					con.close();
					log("Close connection");
				}catch(SQLException e){
					log("Can't close connection");
				}
			}
		}
	}
	
	public synchronized void release(){
		Iterator all=free.iterator();
		while(all.hasNext()){
			Connection con=(Connection)all.next();
			try{
				con.close();
				log("Closed connection for pool on release");
			}catch(SQLException e){
				log("Can't close connection for pool on release");
			}
		}
		free.clear();
	}
	
	private void log(String str) {
		log.println(str);
	}
}
